/*
 * Copyright 2017 yetao &lt;yetao_ustc@163.com&gt;.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package date.yetao.maven.all.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * 本类用于封装字符串的相关操作
 *
 * @author yetao &lt;yetao_ustc@163.com&gt;
 */
public class StringTools {

    /**
     * 查找给定的字符串在字符串数组的哪个位置，-1：没有找到 -10：字符串数组为空
     * <P>
     *
     * @param findstr
     * @param targetstrings
     * @return
     */
    public static int getPosition(String findstr, String[] targetstrings) {
        if (targetstrings == null || targetstrings.length == 0) {
            //-10代表输入目标字符串数组为空或长度为0
            return -10;
        }
        int i;
        if (findstr == null) {
            for (i = 0; i < targetstrings.length; i++) {
                if (targetstrings[i] == null) {
                    break;
                }
            }
        } else {
            for (i = 0; i < targetstrings.length; i++) {
                if (findstr.equals(targetstrings[i])) {
                    break;
                }
            }
        }
        if (i == targetstrings.length) {
            //-1代表没有找到
            return -1;
        } else {
            return i;
        }
    }

    /**
     * 批量替换字符串中的字符，字符串数组一一对应
     * <P>
     *
     * @param replacestr 待替换的模板字符串
     * @param originstrs 需要查找的字符串
     * @param newstrs 新的字符串
     * @param needbreak 是否仅替换第一个，false—全部替换
     * @return
     */
    public static String replaceAll(String replacestr, String[] originstrs, String[] newstrs, boolean needbreak) {
        return replaceAll(replacestr, originstrs, newstrs, needbreak, false);
    }

    /**
     * 批量替换字符串中的字符，字符串数组一一对应
     * <P>
     *
     * @param replacestr 待替换的模板字符串
     * @param originstrs 需要查找的字符串
     * @param newstrs 新的字符串
     * @param needbreak 是否仅替换第一个，false—全部替换
     * @param lengthFirst 长的在前面替换（确保替换的正确性）
     * @return
     */
    public static String replaceAll(String replacestr, String[] originstrs, String[] newstrs, boolean needbreak, boolean lengthFirst) {
        if (replacestr == null || originstrs == null || newstrs == null || originstrs.length != newstrs.length) {
            return null;
        }
        Map<String, String> map = new LinkedHashMap<>();
        for (int i = 0; i < originstrs.length; i++) {
            map.put(originstrs[i], newstrs[i]);
        }
        return replaceAll(replacestr, map, needbreak, lengthFirst);
    }

    /**
     * 批量替换字符串中的字符，字符串数组一一对应
     * <P>
     *
     * @param replacestr 待替换的模板字符串
     * @param replaceMap 替换的字符串映射
     * @param needbreak 是否仅替换第一个，false—全部替换
     * @return
     */
    public static String replaceAll(String replacestr, Map<String, String> replaceMap, boolean needbreak) {
        return replaceAll(replacestr, replaceMap, needbreak, false);
    }

    /**
     * 批量替换字符串中的字符，字符串数组一一对应
     * <P>
     *
     * @param replacestr 待替换的模板字符串
     * @param replaceMap 替换的字符串映射
     * @param needbreak 是否仅替换第一个，false—全部替换
     * @param lengthFirst 长的在前面替换（确保替换的正确性）
     * @return
     */
    public static String replaceAll(String replacestr, Map<String, String> replaceMap, boolean needbreak, boolean lengthFirst) {
        // 判断参数的正确性
        if (replacestr == null) {
            return null;
        }
        if (replaceMap == null) {
            return replacestr;
        }
        String rstr = replacestr;
        // 根据lengthFirst确定是否需要重排
        if (lengthFirst) {
            List<String> keyList = new ArrayList<>(replaceMap.keySet());
            // 重排，长的排在前面
            Collections.sort(keyList, new Comparator<String>() {

                @Override
                public int compare(String o1, String o2) {
                    // 按照长度的倒序排列
                    int sub = -(o1.length() - o2.length());
                    return sub == 0 ? o1.compareTo(o2) : sub;
                }
            });
            // 按照新的顺序组装map
            Map<String, String> newMap = new LinkedHashMap<>();
            for (String key : keyList) {
                newMap.put(key, replaceMap.get(key));
            }
            // 替换掉replaceMap
            replaceMap = newMap;
        }

        // 逐个替换字符串
        for (Map.Entry<String, String> entry : replaceMap.entrySet()) {
            if (rstr.contains(entry.getKey())) {
                rstr = rstr.replace(entry.getKey(), entry.getValue());
                if (needbreak) {
                    break;
                }
            }
        }
        return rstr;
    }

    /**
     * 替换所有的指定字符串，被替换的字符串格式为$$key$$，用于唯一标识需要替换的值
     * <P>
     *
     * @param replacestr
     * @param replaceMap
     * @return
     */
    public static String replaceWith2Dollar(String replacestr, Map<String, String> replaceMap) {
        String content = replacestr;
        for (Map.Entry<String, String> entry : replaceMap.entrySet()) {
            content = content.replace(String.format("$$%s$$", entry.getKey()), entry.getValue());
        }
        return content;
    }

    /**
     * 获取字符串开头的整数，输入的字符串必须是Trim后的，本函数不进行Trim操作，未找到返回最小的整数
     * <P>
     * 本函数只能处理不带符号的整数
     * <P>
     *
     * @param inputStr
     * @return
     */
    public static int getBeginIntInString(String inputStr) {
        char[] numchars = new char[20];   // 最多20位整数
        int length = 0;
        for (int i = 0; i < inputStr.length(); i++) {
            char num = inputStr.charAt(i);
            if (num >= '0' && num <= '9') {
                numchars[i] = num;
                length++;
            } else {
                break;
            }
        }
        // 判断是否找到
        if (length == 0) {
            return Integer.MIN_VALUE;
        }
        return Integer.parseInt(String.copyValueOf(numchars, 0, length));
    }

    /**
     * 获取字符串开头的数字，输入的字符串必须是Trim后的，本函数不进行Trim操作
     * <P>
     * 本函数只能处理不带符号的数字
     * <P>
     *
     * @param inputStr
     * @return
     */
    public static String getBeginNumberString(String inputStr) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < inputStr.length(); i++) {
            char num = inputStr.charAt(i);
            if (num >= '0' && num <= '9') {
                sb.append(num);
            } else {
                break;
            }
        }
        return sb.toString();
    }

    /**
     * 获取字符串开头的数字，输入的字符串必须是Trim后的，本函数不进行Trim操作
     * <P>
     * 本函数只能处理不带符号的数字
     * <P>
     *
     * @param inputStr
     * @return
     */
    public static String getEndNumberString(String inputStr) {
        StringBuilder sb = new StringBuilder();
        for (int i = inputStr.length() - 1; i >= 0; i--) {
            char num = inputStr.charAt(i);
            if (num >= '0' && num <= '9') {
                sb.append(num);
            } else {
                break;
            }
        }
        return sb.reverse().toString();
    }

    /**
     * 本方法用于获取类似于打印页面的分割列表
     * <P>
     * 如：P01-P08,P10,P25-P27等
     * <P>
     *
     * @param pageInfo
     * @return
     * @throws Exception
     */
    public static List<String> getPageList(String pageInfo) throws Exception {
        if (pageInfo == null) {
            return null;
        }
        List<String> resultList = new ArrayList<>();
        // 按照逗号进行分割
        String[] multiParts = pageInfo.split(",");
        trimArray(multiParts);
        for (String multi : multiParts) {
            // 按照-进行分割
            String[] singleParts = multi.split("-");
            trimArray(singleParts);
            if (singleParts.length == 1) {
                resultList.add(singleParts[0]);
            } else if (singleParts.length == 2) {
                // 判断两部分长度是否相等
                if (singleParts[0].length() != singleParts[1].length()) {
                    throw new Exception("【" + singleParts[0] + "】与【" + singleParts[1] + "】的长度不相等！");
                }
                // 判断数字的长度
                int count = 0;
                for (int i = singleParts[0].length() - 1; i >= 0; i--) {
                    char char0 = singleParts[0].charAt(i);
                    char char1 = singleParts[1].charAt(i);
                    System.out.println(char0 + "、" + char1);
                    if (char0 >= '0' && char0 <= '9' && char1 >= '0' && char1 <= '9') {
                        count++;
                    } else {
                        break;
                    }
                }
                if (count <= 0) {
                    throw new Exception("【" + multi + "】不符合规范，末位不是数字！");
                }
                String front0 = singleParts[0].substring(0, singleParts[0].length() - count);
                String front1 = singleParts[1].substring(0, singleParts[1].length() - count);
                String after0 = singleParts[0].substring(singleParts[0].length() - count);
                String after1 = singleParts[1].substring(singleParts[1].length() - count);
                if (!front0.equals(front1)) {
                    throw new Exception("【" + multi + "】不符合规范，两前缀不相同！");
                }
                int begin = Integer.parseInt(after0);
                int end = Integer.parseInt(after1);
                if (begin > end) {
                    throw new Exception("【" + multi + "】不符合规范，前者编号大于后者！");
                }
                for (int i = begin; i <= end; i++) {
                    resultList.add(front0 + String.format("%0" + count + "d", i));
                }
            } else {
                throw new Exception("【" + multi + "】不符合规范！");
            }
        }
        return resultList;
    }

    /**
     * 将字字符串数组进行trim操作
     * <P>
     *
     * @param strs
     */
    public static void trimArray(String[] strs) {
        if (strs == null) {
            return;
        }
        for (int i = 0; i < strs.length; i++) {
            strs[i] = strs[i].trim();
        }
    }

    /**
     * 将文本中全部都为数字（以空格分割）的行，解析为数字的字符串数组
     * <P>
     * 所解析的行必须全部为数字类型
     * <P>
     *
     * @param content 文本内容
     * @param count 指定数字的个数
     * @param continuous 指定是否只取连续的数据
     * @return
     * @throws Exception
     */
    public static String[][] getNumberStringArrays(String content, int count, boolean continuous) throws Exception {
        ArrayList<String[]> rownums = new ArrayList<>();
        if (content == null) {
            return null;
        }
        // 分割行
        String[] lines = content.split("\n");
        for (String line : lines) {
            // 舍弃空行
            if (line.trim().equals("")) {
                rownums.add(null);
                continue;
            }
            // 分割空格字符串
            String[] parts = line.split(" ");
            // 找到是数据的字符串
            ArrayList<String> numparts = new ArrayList<>();
            for (String part : parts) {
                // 舍弃分割多出来的空字符串
                if (part.trim().equals("")) {
                    continue;
                }
                // 判断是否为数字，不是全部为数字则退出for循环，将numparts置为null标识
                try {
                    Double.parseDouble(part.trim());
                    numparts.add(part.trim());
                } catch (NumberFormatException ex) {
                    numparts = null;
                    break;
                }
            }
            // 没有数据或数据解析时出现了问题，则忽略此行
            if (numparts == null || numparts.isEmpty()) {
                rownums.add(null);
                continue;
            }

            String[] nums = new String[numparts.size()];
            nums = numparts.toArray(nums);
            rownums.add(nums);
        }
        if (rownums.isEmpty()) {
            return null;
        }
        // 根据是否指定每行数据个数，过滤数据
        if (count > 0) {
            for (int i = rownums.size() - 1; i >= 0; i--) {
                String[] tempnums = rownums.get(i);
                if (tempnums == null) {
                    continue;
                }
                // 将不符合长度条件的行置为null
                if (tempnums.length != count) {
                    rownums.set(i, null);
                }
            }
        }
        // 统计数据块
        ArrayList<ArrayList<String[]>> allRequiredLines = new ArrayList<>();
        ArrayList<String[]> newrownums = new ArrayList<>();
        for (String[] linenums : rownums) {
            if (linenums == null) {
                if (!newrownums.isEmpty()) {
                    allRequiredLines.add(newrownums);
                    newrownums = new ArrayList<>();
                }
                continue;
            }
            newrownums.add(linenums);
        }
        // 加入最后一组数据
        if (!newrownums.isEmpty()) {
            allRequiredLines.add(newrownums);
        }
        // 不存在满足要求的数据，直接返回null
        if (allRequiredLines.isEmpty()) {
            return null;
        }
        // 根据是否要求连续性统计数据
        ArrayList<String[]> usefulenums = new ArrayList<>();
        if (continuous) {
            if (allRequiredLines.size() > 1) {
                throw new Exception("存在多部分数据满足要求");
            }
            usefulenums = allRequiredLines.get(0);
        } else {
            for (ArrayList<String[]> allRequiredLine : allRequiredLines) {
                usefulenums.addAll(allRequiredLine);
            }
        }
        // 传出数据
        String[][] numstrs = new String[usefulenums.size()][];
        for (int i = 0; i < numstrs.length; i++) {
            numstrs[i] = usefulenums.get(i);
        }
        return numstrs;
    }

    /**
     * 将实数组转化为字符串数组
     * <P>
     *
     * @param datas
     * @return
     */
    public static String[][] toStrArray(double[][] datas) {
        String[][] dataStrs = new String[datas.length][];
        for (int i = 0; i < datas.length; i++) {
            String[] rowDatas = new String[datas[i].length];
            for (int j = 0; j < rowDatas.length; j++) {
                rowDatas[j] = String.valueOf(datas[i][j]);
            }
            dataStrs[i] = rowDatas;
        }
        return dataStrs;
    }

    /**
     * 将字符串数组转化为实数数组
     * <P>
     *
     * @param strDatas
     * @return
     */
    public static double[][] toDoubleArray(String[][] strDatas) {
        double[][] doubleDatas = new double[strDatas.length][];
        for (int i = 0; i < strDatas.length; i++) {
            double[] rowDatas = new double[strDatas[i].length];
            for (int j = 0; j < rowDatas.length; j++) {
                rowDatas[j] = Double.parseDouble(strDatas[i][j]);
            }
            doubleDatas[i] = rowDatas;
        }
        return doubleDatas;
    }

    /**
     * 将ID连城字符串，以,号相连
     * <P>
     *
     * @param ids
     * @return
     */
    public static <T> String joinIdWithComa(T[] ids) {
        List<T> idList = null;
        if (ids != null) {
            idList = Arrays.asList(ids);
        }
        return joinIdWithComa(idList);
    }

    /**
     * 将ID连城字符串，以,号相连
     * <P>
     *
     * @param idList
     * @return
     */
    public static String joinIdWithComa(List<?> idList) {
        StringBuilder sb = new StringBuilder("");
        if (idList == null || idList.isEmpty()) {
            return sb.toString();
        }
        for (Object id : idList) {
            sb.append(id).append(",");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }

    /**
     * 将内容分割成列表，分割后空的字符串（没有实际内容的字符串）不添加到列表中
     * <P>
     *
     * @param content
     * @return 如果不存在或者为null，则返回一个空的列表
     */
    public static List<String> splitStrWithComa(String content) {
        return splitStrWithComa(content, true);
    }

    /**
     * 将内容分割成列表
     * <P>
     *
     * @param content
     * @param ignoreEmptyStr 是否忽略分割后空的字符串（没有实际内容的字符串）
     * @return 如果不存在或者为null，则返回一个空的列表
     */
    public static List<String> splitStrWithComa(String content, boolean ignoreEmptyStr) {
        List<String> idList = new ArrayList<>();
        if (content == null || content.trim().length() == 0) {
            return idList;
        }
        String[] parts = content.split(",");
        for (String p : parts) {
            // 如果忽略空的字符串，且字符串为空，则不添加
            if (ignoreEmptyStr && !hasText(p)) {
                continue;
            }
            idList.add(p);
        }
        return idList;
    }

    /**
     * 判断某个字符串是否有长度，如果为null或者null返回false，其余为true
     * <P>
     *
     * @param text
     * @return
     */
    public static boolean hasLength(String text) {
        return (text != null && !text.equals(""));
    }

    /**
     * 判断某个字符串是否包含有内容，只有当字符串trim()后长度仍然大于0才返回true
     * <P>
     *
     * @param text
     * @return
     */
    public static boolean hasText(String text) {
        if (text == null) {
            return false;
        }
        return text.trim().length() > 0;
    }

    /**
     * 去除字符串中间的空格
     * <P>
     *
     * @param str
     * @return
     */
    public static String trimInnerBlank(String str) {
        return str.replace(" ", "");
    }

    /**
     * 对字符串进行trim操作，同时如果字符串为空，则返回null
     * <P>
     *
     * @param str 需要处理的字符串，null安全
     * @return
     */
    public static String emptyToNullTrim(String str) {
        if (str == null) {
            return null;
        }
        String trim = str.trim();
        return trim.equals("") ? null : trim;
    }

    /**
     * 判断字符串是否为null，如果为null则返回空字符串，不为null返回字符串本身
     * <P>
     *
     * @param str
     * @return
     */
    public static String nullToEmptyStr(String str) {
        return str == null ? "" : str;
    }

    /**
     * 检查列表中的字符串是否都是唯一的，都是唯一的返回true，否则返回false
     * <P>
     * 本方法非null安全的
     * <P>
     *
     * @param forCheck 待检测的字符串列表
     * @return
     */
    public static boolean checkUnique(List<String> forCheck) {
        return checkUnique(forCheck, false, false);
    }

    /**
     * 检查列表中的字符串是否都是唯一的，都是唯一的返回true，否则返回false
     * <P>
     * 本方法非null安全的
     * <P>
     *
     * @param forCheck 待检测的字符串列表
     * @param trim 是否进行trim操作
     * @return
     */
    public static boolean checkUnique(List<String> forCheck, boolean trim) {
        return checkUnique(forCheck, trim, false);
    }

    /**
     * 检查列表中的字符串是否都是唯一的，都是唯一的返回true，否则返回false
     * <P>
     * 本方法非null安全的
     * <P>
     *
     * @param forCheck 待检测的字符串列表
     * @param trim 是否进行trim操作
     * @param ignoreCase 是否忽略大小写
     * @return
     */
    public static boolean checkUnique(List<String> forCheck, boolean trim, boolean ignoreCase) {
        Set<String> existSet = new HashSet<>();
        for (String check : forCheck) {
            // 进行数据格式化的操作
            if (trim) {
                check = check.trim();
            }
            if (ignoreCase) {
                check = check.toLowerCase();
            }
            // 判断是否存在于列表中
            if (existSet.contains(check)) {
                LogUtils.info("存在重复的记录：" + check);
                return false;
            }
            existSet.add(check);
        }
        // 不存在重复的记录
        return true;
    }

    /**
     * 将首字符转化为小写
     * <P>
     *
     * @param s
     * @return
     */
    public static String toLowerCaseFirstOne(String s) {
        if (s == null || s.length() == 0 || Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

    /**
     * 将首字符转化为大写
     * <P>
     *
     * @param s
     * @return
     */
    public static String toUpperCaseFirstOne(String s) {
        if (s == null || s.length() == 0 || Character.isUpperCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

    /**
     * 将字符串转化为小写
     * <P>
     *
     * @param s
     * @return
     */
    public static String toLowerCase(String s) {
        if (s == null || s.length() == 0) {
            return s;
        } else {
            return s.toLowerCase();
        }
    }

    /**
     * 将字符串转化为大写
     * <P>
     *
     * @param s
     * @return
     */
    public static String toUpperCase(String s) {
        if (s == null || s.length() == 0) {
            return s;
        } else {
            return s.toUpperCase();
        }
    }

    /**
     * 根据指定的字符串对给定的字符串进行分割
     * <P>
     * 分割时会自动处理.与|等特殊字符
     * <P>
     *
     * @param content
     * @param splitStr
     * @return
     */
    public static String[] split(String content, String splitStr) {
        switch (splitStr) {
            case ".":
                splitStr = "\\.";
                break;
            case "|":
                splitStr = "\\|";
                break;
        }

        return content.split(splitStr);
    }

    /**
     * 获取指定最大长度的字符串，如果长度不够，则返回实际的字符串
     * <P>
     *
     * @param ori 原始字符串
     * @param start 第一个位置为0
     * @param length 获取的最大长度
     * @return
     */
    public static String getMaxLengthStr(String ori, int start, int length) {
        if (ori == null) {
            return null;
        }
        if (ori.length() <= start) {
            return "";
        }
        if (ori.length() <= start + length) {
            // 长度不够
            return ori.substring(start);
        } else {
            // 长度超过
            return ori.substring(start, start + length);
        }
    }

    /**
     * 获取指定最大长度的字符串，如果长度不够，则返回实际的字符串
     * <P>
     *
     * @param ori 原始字符串
     * @param length 获取的最大长度
     * @return
     */
    public static String getMaxLengthStr(String ori, int length) {
        return getMaxLengthStr(ori, 0, length);
    }

    /**
     * 驼峰命名法工具，将下划线连接的字符串改为驼峰法命名
     * <P>
     *
     * @param str 需要转化的字符串
     * @param firstUpper 第一个字母是否大写
     * @return toCamelCase("hello_world") == "helloWorld"
     * toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String fromUnderToCamelCase(String str, boolean firstUpper) {
        char SEPARATOR = '_';

        // 字符串为空直接返回
        if (str == null) {
            return null;
        }

        str = str.toLowerCase().trim();

        // 构建对象
        StringBuilder sb = new StringBuilder();
        boolean upperCase = false;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (i == 0 && firstUpper) {
                c = Character.toUpperCase(c);
            }

            if (c == SEPARATOR) {
                upperCase = true;
            } else if (upperCase) {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            } else {
                sb.append(c);
            }
        }

        return sb.toString();
    }

    /**
     * 驼峰命名法工具，将驼峰法命名改为下划线连接的字符串
     * <P>
     *
     * @param str 需要转化的字符串
     * @return toCamelCase("hello_world") == "helloWorld"
     * toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String fromCamelToUnderCase(String str) {
        char SEPARATOR = '_';
        if (str == null) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        boolean upperCase = false;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);

            boolean nextUpperCase = true;

            if (i < (str.length() - 1)) {
                nextUpperCase = Character.isUpperCase(str.charAt(i + 1));
            }

            if ((i > 0) && Character.isUpperCase(c)) {
                if (!upperCase || !nextUpperCase) {
                    sb.append(SEPARATOR);
                }
                upperCase = true;
            } else {
                upperCase = false;
            }

            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }

    /**
     * 所引致指定的位置进行字符串切割
     * <P>
     *
     * @param ori 原始字符串
     * @param index 定位字符串
     * @return
     */
    public static String subStringByIndex(String ori, String index) {
        return subStringByIndex(ori, index, false);
    }

    /**
     * 所引致指定的位置进行字符串切割
     * <P>
     *
     * @param ori 原始字符串
     * @param index 定位字符串
     * @param with 是否包括索引的字符串
     * @return
     */
    public static String subStringByIndex(String ori, String index, boolean with) {
        if (ori == null || !ori.contains(index)) {
            return ori;
        }
        // 切割字符串
        return ori.substring(0, with ? ori.indexOf(index) + index.length() : ori.indexOf(index));
    }

    /**
     * 将原始字符串的分割符号，转化为Linux的\n
     * <P>
     *
     * @param ori
     * @return
     */
    public static String toLinuxLineSeparate(String ori) {
        if (ori == null) {
            return ori;
        }
        ori = ori.replace("\r\n", "\n");
        ori = ori.replace("\r", "\n");
        return ori;
    }

    /**
     * 自动将字符串拆分成为一段一段的，拆分字符有：,，|\/. \t-_等
     * <P>
     *
     * @param ori
     * @return
     */
    public static List<String> smartSplit(String ori) {
        if (ori == null) {
            return null;
        }
        // 组装替换Map
        // 此处定义可能的分割符号，暂时不全部使用
        List<String> splitList = Arrays.asList("！", "!", "“", "”", "\"", "#", "%", ",", "，", "（", "）", ":", "：", "；", ";", ".", "。", "/", "=", "？", "?", "|", "\\", "\t", "-", "_");
        Map<String, String> repMap = new HashMap<>();
        for (String split : splitList) {
            repMap.put(split, " ");
        }
//        repMap.put(",", " ");
//        repMap.put("，", " ");
//        repMap.put("|", " ");
//        repMap.put("\\", " ");
//        repMap.put("/", " ");
//        repMap.put(".", " ");
//        repMap.put("\t", " ");
//        repMap.put("-", " ");
//        repMap.put("_", " ");
        String result = replaceAll(ori, repMap, false);
        String[] parts = result.split(" ");
        List<String> list = new ArrayList<>();
        for (String part : parts) {
            if (hasText(part)) {
                list.add(part);
            }
        }
        return list;
    }

    /**
     * 取智能分割后的第一段字符
     * <P>
     *
     * @param ori
     * @return
     */
    public static String smartSplitFirstPart(String ori) {
        List<String> list = smartSplit(ori);
        return (list == null || list.isEmpty()) ? null : list.get(0);
    }

    /**
     * 判断字符是否是A-Z或a-z或0-9
     * <P>
     *
     * @param c
     * @return
     */
    public static boolean isAZaz09(char c) {
        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
    }

    /**
     * 判断字符是否是A-Z或a-z
     * <P>
     *
     * @param c
     * @return
     */
    public static boolean isAZaz(char c) {
        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
    }

    /**
     * 判断字符是否是A-Z
     * <P>
     *
     * @param c
     * @return
     */
    public static boolean isAZ(char c) {
        return (c >= 'A' && c <= 'Z');
    }

    /**
     * 判断字符是否是a-z
     * <P>
     *
     * @param c
     * @return
     */
    public static boolean isaz(char c) {
        return (c >= 'a' && c <= 'z');
    }

    /**
     * 去除字符串末尾的数字并返回
     * <P>
     *
     * @param str
     * @return
     */
    public static String trimLastNumber(String str) {
        if (str == null) {
            return null;
        }
        // 定位最后一个不为数字的字符
        int idx = str.length() - 1;
        for (; idx >= 0; idx--) {
            char c = str.charAt(idx);
            if (c < '0' || c > '9') {
                break;
            }
        }
        return str.substring(0, idx + 1);
    }

    /**
     * 获取最大频率字符串的辅助方法
     * <P>
     *
     * @param list
     * @return
     */
    public static String getMaxFrequencyStr(Collection<String> list) {
        // 检查数据的合法性
        if (list == null || list.isEmpty()) {
            throw new RuntimeException("The collection can no be null or empty.");
        }
        Map<String, Integer> countMap = new HashMap<>();
        for (String key : list) {
            Integer count = countMap.get(key);
            if (count == null) {
                count = 0;
                countMap.put(key, count);
            }
            count = count + 1;
            countMap.put(key, count);
        }
        // 排序取最大的进行处理
        List<Map.Entry<String, Integer>> resList = new ArrayList<>(countMap.entrySet());
        Collections.sort(resList, new Comparator<Map.Entry<String, Integer>>() {

            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return -o1.getValue().compareTo(o2.getValue());
            }

        });
        // 返回最大的第一个数据
        return resList.get(0).getKey();
    }

    /**
     * 判断字符串的第一个字母是否是大写
     * <P>
     *
     * @param str
     * @return
     */
    public static boolean isFirstUpperCase(String str) {
        if (str == null || str.length() == 0) {
            return false;
        }
        return Character.isUpperCase(str.charAt(0));
    }

    /**
     * 切割并连接两个字符串
     * <P>
     *
     * @param frontStr 前面的字符串
     * @param frontStart 前面字符串的开始位置
     * @param frontLength 前面字符串截取的长度
     * @param afterStr 后面的字符串
     * @param afterStart 后面的字符串的开始位置
     * @param afterLength 后面的字符串的长度
     * @return
     */
    public static String splitAndJoin(String frontStr, int frontStart, int frontLength, String afterStr, int afterStart, int afterLength) {
        return splitAndJoin(frontStr, frontStart, frontLength, afterStr, afterStart, afterLength, "");
    }

    /**
     * 切割并连接两个字符串
     * <P>
     *
     * @param frontStr 前面的字符串
     * @param frontStart 前面字符串的开始位置
     * @param frontLength 前面字符串截取的长度
     * @param afterStr 后面的字符串
     * @param afterStart 后面的字符串的开始位置
     * @param afterLength 后面的字符串的长度
     * @param joinStr 连接的字符串
     * @return
     */
    public static String splitAndJoin(String frontStr, int frontStart, int frontLength, String afterStr, int afterStart, int afterLength, String joinStr) {
        StringBuilder sb = new StringBuilder();
        sb.append(frontStr.substring(frontStart, Math.min(frontStr.length(), frontStart + frontLength)))
                .append(joinStr)
                .append(afterStr.substring(afterStart, Math.min(afterStr.length(), afterStart + afterLength)));
        return sb.toString();
    }

    /**
     * 给定的字符串是否包含任意一个字符
     *
     * @param str
     * @param specialSet
     * @return
     */
    public static boolean containsAnyChar(String str, Set<Character> specialSet) {
        if (str == null) {
            return false;
        }
        for (char ch : str.toCharArray()) {
            if (specialSet.contains(ch)) {
                return true;
            }
        }
        return false;
    }

}
